package com.qianfeng.smartplatform.service.impl;

//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼                  BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  
//  


import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qianfeng.smartplatform.cache.CategoriesCache;
import com.qianfeng.smartplatform.constants.ResultCode;
import com.qianfeng.smartplatform.event.CategoryChangeEvent;
import com.qianfeng.smartplatform.exceptions.AddDataException;
import com.qianfeng.smartplatform.exceptions.DeleteDataException;
import com.qianfeng.smartplatform.mapper.SysCategoryMapper;
import com.qianfeng.smartplatform.pojo.CheckType;
import com.qianfeng.smartplatform.pojo.MyBaseUser;
import com.qianfeng.smartplatform.pojo.SysCategory;
import com.qianfeng.smartplatform.service.SysCategoryService;
import com.qianfeng.smartplatform.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by Jackiechan on 2022/5/27 10:04
 *
 * @author Jackiechan
 * @version 1.0
 * @since 1.0
 */
@Transactional
@Service
public class SysCategoryServiceImpl implements SysCategoryService {


    private ApplicationContext context;

    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    private CategoriesCache categoriesCache;

    @Autowired
    public void setCategoriesCache(CategoriesCache categoriesCache) {
        this.categoriesCache = categoriesCache;
    }

    private SysCategoryMapper sysCategoryMapper;

    @Autowired
    public void setSysCategoryMapper(SysCategoryMapper sysCategoryMapper) {
        this.sysCategoryMapper = sysCategoryMapper;
    }

    @Override
    public void addCategory(SysCategory sysCategory) {
        //需要对数据进行校验
        Assert.isTrue(!sysCategory.isEmpty(CheckType.ADD), () -> {
            throw new AddDataException("传递的数据不完整", ResultCode.DATA_NULL);
        });

        //必须知道当前创建者是谁, 那就意味着我们必须知道当前的登录用户是谁,也就意味着当前操作必须登录才可以操作
        //假设我们前面已经进行了用户的登录拦截,那么在这里如何获取到用户
        //我们在用户登录之后将用户的数据保存到了session中,所以在此处可以通过session获取
        //我们可能在很多个不同的操作中都需要获取到用户的信息,那我们可以把获取用户信息的方法封装起来
        //也就是我们需要写一个拦截器来进行拦截
        MyBaseUser sysUserInfo = SecurityUtils.getUserInfo(false);
        //设置创建者为当前登录的用户
        sysCategory.setCreateBy(sysUserInfo.getUsername());
        sysCategoryMapper.addSysCategory(sysCategory);
        //我们现在的策略是数据从缓存中查询,但是现在添加完数据后,缓存根本不知道有这个事情发生了
        //所以缓存中的数据还是之前的数据,那我们需要更新缓存中的数据,告诉缓存兄弟你的数据发生变化了你再去查询一下
        //我们约定好,缓存知道数据可能会随时发生变化,所以让缓存监听一个事件,当发生这个事件的时候就去重新加载缓存
        context.publishEvent(new CategoryChangeEvent());
    }

    @Override
    public PageInfo<SysCategory> findAll(int pageSize, int pageNum) {
        //正常这里要查询数据库,但是我们说了没有必要每次查询数据库,所以在这里肯定是查询其他地方
        //在另外一个地方一定存放了这些数据,并且是在内存里面
        //我们现在是不是从某个位置找数据,问题来了,什么时候会需要用查询这些数据,用户访问的时候
        //什么时候用户会访问? 不知道.所以我们的措施就是程序启动的时候我就加载了一次所有的数据,那么启动后不管用户什么时候访问都有数据
        // TODO 我们现在新增一个要求,之前返回的数据是所有的数据,现在我们要求返回的数据是有效的数据,被标记为删除的数据不返回
        List<SysCategory> categoryList = categoriesCache.getAllEnableList();//从缓存中获取到查询的数据
        //下一步 如果需要分页怎么办?
        PageHelper.startPage(pageNum, pageSize);//开启分页
        List<SysCategory> result = categoryList.stream()
                .skip((pageNum - 1) * pageSize)//跳过多少数据,就是偏移量
                .limit(pageSize)//想要多少数据量,超过的不要
                .collect(Collectors.toList());//收集前面的结果数据
        PageInfo<SysCategory> pageInfo = new PageInfo<>(result);//设置数据
        pageInfo.setTotal(categoryList.size());//设置总长度,之前查询数据库的时候会自动查询并设置,现在我们不查询数据库了我们自己设置
        return pageInfo;
    }

    @Override
    public void deleteById(Long cId) {
        Assert.isTrue(cId > 0, () -> {
            throw new DeleteDataException("主键不符合要求", ResultCode.ID_NOTALLOWED);
        });
        //获取的当前登录的用户的数据
        MyBaseUser sysUserInfo = SecurityUtils.getUserInfo(false);
        //设置更新者为当前登录的用户
        sysCategoryMapper.deleteById(cId, new Date(), sysUserInfo.getUsername());
        //通知缓存,数据发生变化
        context.publishEvent(new CategoryChangeEvent());

    }

    @Override
    public void deleteByIds(List<Long> ids, Long status) {
        Assert.notEmpty(ids, () -> {
            throw new DeleteDataException("主键不符合要求", ResultCode.ID_NOTALLOWED);
        });
        //获取的当前登录的用户的数据
        MyBaseUser sysUserInfo = SecurityUtils.getUserInfo(false);
        sysCategoryMapper.deleteByIds(ids, new Date(), sysUserInfo.getUsername(),status);
        //通知缓存,数据发生变化
        context.publishEvent(new CategoryChangeEvent());
    }
}
